package com.wtf.generator.executor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.annotation.DbType;
import com.wtf.generator.annatation.DbTypeFlag;
import com.wtf.generator.dao.AbstractGeneratorDao;
import com.wtf.generator.enums.CommonErrorEnum;
import com.wtf.generator.exception.CommonException;
import com.wtf.generator.model.dto.DsAddDTO;
import com.wtf.generator.model.dto.DsSqlDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * date: 2022/6/18 10:59
 * @author linhuanyou
 * @email 496558736@qq.com
 * @version 1.0
 */
@Slf4j
@Component
public class DsDbExecutor extends AbstractExecutor{

    private ConcurrentMap<DbType, AbstractGeneratorDao> generatorDaos = new ConcurrentHashMap<DbType, AbstractGeneratorDao>();

    @Override
    protected void initExecutors() {
        String[] beanDefinitionNames = this.applicationContext.getBeanNamesForType(AbstractGeneratorDao.class);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = this.applicationContext.getBean(beanDefinitionName);
            DbTypeFlag dbTypeFlag = AnnotationUtils.findAnnotation(bean.getClass(), DbTypeFlag.class);
            if(dbTypeFlag != null){
                generatorDaos.put(dbTypeFlag.dbType(), (AbstractGeneratorDao)bean);
                log.info("Load The GeneratorDao : {}",bean);
            }
        }
    }

    public <T> T doExecutor(DsSqlDTO dsSqlDTO,TypeReference<T> clazz) throws ClassNotFoundException {
        DbType dbType = dsSqlDTO.getDbType();
        AbstractGeneratorDao abstractGeneratorDao = generatorDaos.get(dbType);
        String excSql = dsSqlDTO.getExcSql();
        Object result ;
        switch (dsSqlDTO.getSqlResponseMapper()){
            case MAP_LIST:
                result = abstractGeneratorDao.queryForList(excSql);
                break;
            case MAP:
                result = abstractGeneratorDao.queryForMap(excSql);
                break;
            case T:
                Class<?> tClass = Class.forName(clazz.getType().getTypeName());
                result = abstractGeneratorDao.queryForObject(excSql,tClass);
                break;
            case T_LIST:
                Class<?> tListClass = Class.forName(clazz.getType().getTypeName());
                result = abstractGeneratorDao.queryForList(excSql,tListClass);
                break;
            default:
                throw new CommonException(CommonErrorEnum.ERROR_VALID);
        }
        return JSONObject.parseObject(JSON.toJSONString(result),clazz);
    }

    private AbstractGeneratorDao getDbDao(DbType dbType){
        return generatorDaos.get(dbType);
    }

    public DataSourceProperty getDataSourceProperty(DsAddDTO dsDbDTO){
        AbstractGeneratorDao dbDao = getDbDao(dsDbDTO.getDbType());
        return dbDao.getDataSourceProperty(dsDbDTO);
    }

    public boolean testConnectDb(DsAddDTO dsDbDTO){
        AbstractGeneratorDao dbDao = getDbDao(dsDbDTO.getDbType());
        if(dbDao == null){
            return false;
        }
        Connection connection = null;
        try {
            connection = dbDao.openConnection(dsDbDTO);
            return true;
        } catch (Exception e) {
            throw new CommonException(CommonErrorEnum.OPEN_CONNECTION_EXCEPTION,e);
        } finally {
            try {
                dbDao.closeConnection(connection);
            } catch (CommonException e) {

            }
        }
    }

    public Properties getDbProperties(String jdbcUrl, DbType dbType) throws Exception {
        AbstractGeneratorDao dbDao = getDbDao(dbType);
        return dbDao.getProperties(jdbcUrl,dbType);
    }

}
